package org.scheduler4j;

/**
 * Time Class, just contain time values.
 * 
 * @author Eric
 * 
 */
public class Time {

	private int hour;
	private int minute;
	private int second;
	private int millisecond;

	/**
	 * default constructor, the time should be 0:0:0 0
	 */
	public Time() {
		super();
	}

	/**
	 * constructor with hour and minute.
	 * 
	 * @param hour
	 *            the hour for time object.
	 * @param minute
	 *            the minute for time object.
	 */
	public Time(int hour, int minute) {
		this();
		setHour(hour);
		setMinute(minute);
	}

	/**
	 * constructor with hour, minute, second.
	 * 
	 * @param hour
	 *            the hour of the Time object.
	 * @param minute
	 *            the minute of the Time object.
	 * @param second
	 *            the second of the Time object.
	 */
	public Time(int hour, int minute, int second) {
		this(hour, minute);
		setSecond(second);
	}

	/**
	 * constructor with hour, minute, second, millisecond.
	 * 
	 * @param hour
	 *            the hour of the Time object.
	 * @param minute
	 *            the minute of the Time object.
	 * @param second
	 *            the second of the Time object.
	 * @param millisecond
	 *            the millisecond of the Time object.
	 */
	public Time(int hour, int minute, int second, int millisecond) {
		this(hour, minute, second);
		setMillisecond(millisecond);
	}

	/**
	 * constructor with time.
	 * 
	 * @param time
	 */
	public Time(int time) {
		if (time < 0 || time > Constants.MAX_TIME) {
			throw new InvalidTimeFormatException("time should be less than "
					+ Constants.MAX_TIME);
		}
		setHour(time / (60 * 60 * 1000));
		setMinute((time % (60 * 60 * 1000)) / (60 * 1000));
		setSecond((time % (60 * 1000)) / 1000);
		setMillisecond(time % 1000);
	}

	/**
	 * constructor with String format time, hh:MM:ss SSS.
	 * 
	 * @param time
	 */
	public Time(String time) {
		if (time == null || time.indexOf(':') < 0 || time.startsWith(":")
				|| time.endsWith(":")) {
			throw new InvalidTimeFormatException("invalid time format : "
					+ time);
		}

		String[] times = time.split(":");
		if (times.length == 1) {
			throw new InvalidTimeFormatException("invalid time format : "
					+ time);
		} else if (times.length == 2) {
			int h = 0, m = 0;
			try {
				h = Integer.parseInt(times[0]);
			} catch (NumberFormatException ex) {
				throw new InvalidHourException("invalid time format : " + time);
			}
			try {
				m = Integer.parseInt(times[1]);
			} catch (NumberFormatException ex) {
				throw new InvalidMinuteException("invalid time format : "
						+ time);
			}
			setHour(h);
			setMinute(m);
		} else if (times.length == 3) {
			int h = 0, m = 0, s = 0, ms = 0;
			try {
				h = Integer.parseInt(times[0]);
			} catch (NumberFormatException ex) {
				throw new InvalidHourException("invalid time format : " + time);
			}
			try {
				m = Integer.parseInt(times[1]);
			} catch (NumberFormatException ex) {
				throw new InvalidMinuteException("invalid time format : "
						+ time);
			}
			String mss[] = times[2].split(" ");
			if (mss.length == 1) {
				try {
					s = Integer.parseInt(mss[0]);
				} catch (NumberFormatException ex) {
					throw new InvalidSecondException("invalid time format : "
							+ time);
				}
			} else if (mss.length == 2) {
				try {
					s = Integer.parseInt(mss[0]);
				} catch (NumberFormatException ex) {
					throw new InvalidSecondException("invalid time format : "
							+ time);
				}
				try {
					ms = Integer.parseInt(mss[1]);
				} catch (NumberFormatException ex) {
					throw new InvalidMillisecondException(
							"invalid time format : " + time);
				}
			} else {
				throw new InvalidTimeFormatException("invalid time format : "
						+ time);
			}
			setHour(h);
			setMinute(m);
			setSecond(s);
			setMillisecond(ms);
		} else {
			throw new InvalidTimeFormatException("invalid time format : "
					+ time);
		}
	}

	/**
	 * return millisecond for this Time object.
	 * 
	 * @return
	 */
	public int getTime() {
		return ((hour * 60 + minute) * 60 + second) * 1000 + millisecond;
	}

	public String toString() {
		return hour + ":" + minute + ":" + second + " " + millisecond;
	}

	@Override
	public int hashCode() {
		return getTime();
	}

	@Override
	public boolean equals(Object obj) {
		if (obj == null || !(obj instanceof Time)) {
			return false;
		}
		Time tmp = (Time) obj;
		return tmp.getTime() == getTime();
	}

	/**
	 * get hour of the Time object.
	 * 
	 * @return
	 */
	public int getHour() {
		return hour;
	}

	public void setHour(int hour) throws InvalidHourException {
		if (hour < 0 || hour > 23) {
			throw new InvalidHourException();
		}
		this.hour = hour;
	}

	/**
	 * get minute of Time object.
	 * 
	 * @return
	 */
	public int getMinute() {
		return minute;
	}

	public void setMinute(int minute) throws InvalidMinuteException {
		if (minute < 0 || minute > 59) {
			throw new InvalidMinuteException();
		}
		this.minute = minute;
	}

	/**
	 * get second of the Time object.
	 * 
	 * @return
	 */
	public int getSecond() {
		return second;
	}

	public void setSecond(int second) throws InvalidSecondException {
		if (second < 0 || second > 59) {
			throw new InvalidSecondException();
		}
		this.second = second;
	}

	/**
	 * get millisecond of Time object.
	 * 
	 * @return
	 */
	public int getMillisecond() {
		return millisecond;
	}

	public void setMillisecond(int millisecond)
			throws InvalidMillisecondException {
		if (millisecond < 0 || millisecond > 999) {
			throw new InvalidMillisecondException();
		}
		this.millisecond = millisecond;
	}
}
